//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#include "LigandPDBFilter.h"

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <zlib.h>

#include <iostream>
#include <fstream>
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
#define LENGTHTEXT 100
#define MINIMUM_NUMBER_ATOMS 10
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
using namespace std;
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
namespace LigandPDB {
  
  bool EqualLigand (TNode <BindingInfo>* bindingInfo, void* ref) {

    bindingInfo->Info()->NearResiduesByLigand()->SetInitial();
    while (bindingInfo->Info()->NearResiduesByLigand()->SetNext()) 
      if (!strcmp(bindingInfo->Info()->NearResiduesByLigand()->GetCurrent()->LigandName()->Out(), ((String*)ref)->Out()))
        return true;
    return false;

  }
  
};
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
LigandPDBFilter::LigandPDBFilter () {
  
  this->bindingProfile         = new ProcessBindingFASTAProfile ();
  this->locationPDBHet         = new String ();
  this->locationPDBOut         = new String ();
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
LigandPDBFilter::LigandPDBFilter (const LigandPDBFilter& ligandPDBFilter) {
  
  this->bindingProfile         = new ProcessBindingFASTAProfile (ligandPDBFilter.bindingProfile);
  this->locationPDBHet         = new String (ligandPDBFilter.locationPDBHet);
  this->locationPDBOut         = new String (ligandPDBFilter.locationPDBOut);
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
LigandPDBFilter::LigandPDBFilter (const LigandPDBFilter* ligandPDBFilter) {
  
  this->bindingProfile         = new ProcessBindingFASTAProfile (ligandPDBFilter->bindingProfile);
  this->locationPDBHet         = new String (ligandPDBFilter->locationPDBHet);
  this->locationPDBOut         = new String (ligandPDBFilter->locationPDBOut);
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
LigandPDBFilter::~LigandPDBFilter () {
  
  if (this->bindingProfile) delete this->bindingProfile;
  if (this->locationPDBHet) delete this->locationPDBHet;
  if (this->locationPDBOut) delete this->locationPDBOut;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void LigandPDBFilter::BindingProfile (ProcessBindingFASTAProfile* bindingProfile) {
  
  if (bindingProfile) *(this->bindingProfile) = *bindingProfile;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void LigandPDBFilter::LocationPDBHet (String* locationPDBHet) {
  
  if (locationPDBHet) this->locationPDBHet->In(locationPDBHet);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
void LigandPDBFilter::LocationPDBOut (String* locationPDBOut) {
  
  if (locationPDBOut) this->locationPDBOut->In(locationPDBOut);
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
ProcessBindingFASTAProfile* LigandPDBFilter::BindingProfile (void) {
  
  return this->bindingProfile;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* LigandPDBFilter::LocationPDBHet (void) {
  
  return this->locationPDBHet;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
String* LigandPDBFilter::LocationPDBOut (void) {
  
  return this->locationPDBOut;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool LigandPDBFilter::LoadData (void) {
  
  if (!this->bindingProfile                                     ||
      !this->bindingProfile->FilenameBindingProfile()           || 
      !this->bindingProfile->FilenameBindingProfile()->Length() ||
      !this->bindingProfile->FilenameListLigands()              || 
      !this->bindingProfile->FilenameListLigands()->Length()    || 
      !this->bindingProfile->LoadData())
    return false;

  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
bool LigandPDBFilter::WritePDBForEachLigand (void) {
  
  if (!this->bindingProfile            || !this->bindingProfile->BindingProfiles()->Length() || 
      !this->bindingProfile->Ligands() || !this->bindingProfile->Ligands()->Length()         ||
      !this->locationPDBHet            || !this->locationPDBHet->Length()                    ||
      !this->locationPDBOut            || !this->locationPDBOut->Length())
    return false;

  String* namefileHetAtm = new String ();
  
  this->bindingProfile->Ligands()->SetInitial();
  while (this->bindingProfile->Ligands()->SetNext()) {
    
    String*      currentLigand     = this->bindingProfile->Ligands()->GetCurrent();
    cout << "Searching for a Ligand: " << currentLigand->Out() << endl;
    
    BindingInfo* searchBindingInfo = this->bindingProfile->BindingProfiles()->FirstOcurrence(LigandPDB::EqualLigand, currentLigand);
    
    if (!searchBindingInfo) { cout << "Error searching the Ligand: " << currentLigand->Out() << endl; continue; }
    
    namefileHetAtm->In(this->locationPDBHet);
    if (namefileHetAtm->Out()[namefileHetAtm->Length() - 1] != '/')
      namefileHetAtm->Add("/");
    namefileHetAtm->Add(searchBindingInfo->Domain());
    
    ListLigand* ligandsInFile = new ListLigand ();
    
    ligandsInFile->FilenameIn(namefileHetAtm);
    ligandsInFile->LoadData();
    
    namefileHetAtm->In(this->locationPDBOut);
    if (namefileHetAtm->Out()[namefileHetAtm->Length() - 1] != '/')
      namefileHetAtm->Add("/");
    namefileHetAtm->Add(currentLigand);
    
    fstream file;
    
    file.open(namefileHetAtm->Out(), fstream::out);
    
    if (!file.is_open()) { cout << "Error writing the info of Ligand: " << currentLigand->Out() << endl; continue; }
    
    ligandsInFile->Ligands()->SetInitial();
    while (ligandsInFile->Ligands()->SetNext()) 
      if (!strcmp(ligandsInFile->Ligands()->GetCurrent()->Name()->Out(), currentLigand->Out())) {
        file << ligandsInFile->Ligands()->GetCurrent()->ToString()->Out();
        break;
      }  
    
    file.close();
    
    if (ligandsInFile) delete ligandsInFile;
     
  }
  
  if (namefileHetAtm) delete namefileHetAtm;
  
  return true;
  
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
LigandPDBFilter  LigandPDBFilter::operator= (const LigandPDBFilter& ligandPDBFilter) {

  *(this->bindingProfile) = *(ligandPDBFilter.bindingProfile);

  this->locationPDBHet->In(ligandPDBFilter.locationPDBHet);
  this->locationPDBOut->In(ligandPDBFilter.locationPDBOut);
  
  return *this;
    
}
//---------------------------------------------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------------------------------------------//

